package com.cloud.gateway.route;

import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.cloud.gateway.properties.NacosRouteProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.context.ApplicationEventPublisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.Executor;

/**
 * @author 王霄
 * @date 2022/8/14 12:26
 */
@Slf4j
@Builder
public class NacosRouteDefinitionRepository implements RouteDefinitionRepository {

    private final NacosRouteProperties properties;
    private final ObjectMapper objectMapper;
    private final ApplicationEventPublisher publisher;
    private final ConfigService configService;


    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        List<RouteDefinition> routeDefinitions = null;
        try {
            String configInfo = configService.getConfig(
                    properties.getRouteDataId(),
                    properties.getRouteGroup(),
                    30000);
            routeDefinitions = objectMapper.readValue(configInfo, new TypeReference<List<RouteDefinition>>() {
            });
        } catch (NacosException | JsonProcessingException e) {
            e.printStackTrace();
        }
        addListener();
        return Flux.fromIterable(Optional.ofNullable(routeDefinitions).orElse(new ArrayList<>()));
    }


    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return null;
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return null;
    }

    private void addListener() {
        try {
            configService.addListener(properties.getRouteDataId(), properties.getRouteGroup(), new Listener() {
                @Override
                public Executor getExecutor() {
                    return null;
                }

                @Override
                public void receiveConfigInfo(String configInfo) {
                    log.info(">>>>>>>>> 监听到路由规则发生改变: {} ", configInfo);
                    publisher.publishEvent(new RefreshRoutesEvent(this));
                }
            });
        } catch (NacosException e) {
            e.printStackTrace();
        }
    }

}

